package com.cardone.common.web.support;

import com.cardone.common.util.MapperUtils;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.*;
import org.springframework.http.converter.*;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;

/**
 * @author yaohaitao
 */
@Slf4j
public class CardOneHttpMessageConverter extends AbstractHttpMessageConverter<Object> implements org.springframework.http.converter.GenericHttpMessageConverter<Object> {
    @Setter
    @Getter
    private Charset charset = Charsets.UTF_8;

    public CardOneHttpMessageConverter() {
        super(new MediaType(com.google.common.net.MediaType.ANY_APPLICATION_TYPE.type(), com.google.common.net.MediaType.ANY_APPLICATION_TYPE.subtype(), Charsets.UTF_8), new MediaType(com.google.common.net.MediaType.ANY_APPLICATION_TYPE.type(), "*+json", Charsets.UTF_8));
    }

    @Override
    protected boolean supports(final Class<?> clazz) {
        return true;
    }

    @Override
    protected Object readInternal(final Class<? extends Object> clazz, final HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        String jsonString = null;

        try {
            jsonString = IOUtils.toString(inputMessage.getBody(), this.charset);
        } catch (final Exception e) {
            CardOneHttpMessageConverter.log.error(e.getMessage(), e);
        }

        if (StringUtils.isBlank(jsonString)) {
            return null;
        }

        CardOneHttpMessageConverter.log.debug(jsonString);

        if (String.class.equals(clazz)) {
            return jsonString;
        }

        return MapperUtils.getBeanForJson(clazz, jsonString);
    }

    @Override
    protected void writeInternal(final Object obj, final HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        final String jsonString = MapperUtils.toJson(obj);

        CardOneHttpMessageConverter.log.debug(jsonString);

        final byte[] bytes = jsonString.getBytes(this.charset);

        if (org.apache.commons.lang.ArrayUtils.isEmpty(bytes)) {
            return;
        }

        try (OutputStream out = outputMessage.getBody()) {
            out.write(bytes);

            out.flush();
        }
    }

    @Override
    public boolean canRead(java.lang.reflect.Type type, Class<?> aClass, org.springframework.http.MediaType mediaType) {
        return canRead(mediaType);
    }

    @Override
    public Object read(java.lang.reflect.Type type, Class<?> clazz, org.springframework.http.HttpInputMessage httpInputMessage) throws java.io.IOException, org.springframework.http.converter.HttpMessageNotReadableException {
        String jsonString = null;

        try {
            jsonString = IOUtils.toString(httpInputMessage.getBody(), this.charset);
        } catch (final Exception e) {
            CardOneHttpMessageConverter.log.error(e.getMessage(), e);
        }

        if (StringUtils.isBlank(jsonString)) {
            return null;
        }

        CardOneHttpMessageConverter.log.debug(jsonString);

        if (String.class.equals(clazz)) {
            return jsonString;
        }

        com.google.gson.reflect.TypeToken<?> token = com.google.gson.reflect.TypeToken.get(type);

        return MapperUtils.getBeanForJson(token.getType(), jsonString);
    }
}
